#include "headers.h"


static int MOUSE_STATE;
static int MOUSE_BUTTON;

static GLdouble EYE_X;
static GLdouble EYE_Y;
static GLdouble EYE_Z;

static GLdouble t_x, t_y, t_z;

/* angulos que estao no intervalo[0,PI] */
static GLdouble PHI;
static GLdouble RHO; /* se x = 0, rotaciona em YZ */
static GLdouble THETA; /* se z = 0, rotaciona em XY */

static GLfloat WHITE[] = {1.0, 1.0, 1.0, 0.0};
static GLfloat BLACK[] = {0.0, 0.0, 0.0, 0.0};

static int oldX, oldY;

static GLfloat vertices[] = {1., 0., 0.,
			     0., 1., 0.,
			     0., 0., 1.};

static GLfloat colors[] = {1.0, 0.0, 0.0,
			   0.0, 1.0, 0.0,
			   0.0, 0.0, 1.0};

static float width, height;

void reset() {
  RHO = 2.0;
  THETA = PI/4;
  PHI = PI/4;
  t_x = t_y = t_z = 0.0;
}

void updateEyes() {
  EYE_X = RHO * cos(THETA) * cos(PHI);
  EYE_Y = RHO * sin(PHI);
  EYE_Z = RHO * sin(THETA) * cos(PHI);
}

void updateAngles(int x, int y) {
  THETA += (x - oldX) * 0.01;
  
  PHI += (y - oldY) * 0.01;
  if(PHI <= 0.0) PHI = 0.0;         
  if(PHI >= PI / 2.0) PHI = PI / 2.0 - 0.0001;
}


void createLists(void) {
  int i;  
  
  glNewList(TRIANGLE_LIST, GL_COMPILE);
  glEnableClientState (GL_COLOR_ARRAY);
  glEnableClientState (GL_VERTEX_ARRAY);
  glColorPointer (3, GL_FLOAT, 0, colors);
  glVertexPointer (3, GL_FLOAT, 0, vertices);
  
  glBegin(GL_TRIANGLES);
  for (i = 0; i < 3; i++)
    glArrayElement(i);
  glEnd();
  glEndList();
}

void init(void)
{
  //glClearColor(1.0, 1.0, 1.0, 0.0); /* fundo branco */
  glClearColor(0.0, 0.0, 0.0, 0.0);  /* fundo preto */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  //glOrtho(-7.0, 7.0, -7.0, 7.0, -7.0, 7.0);
  //gluLookAt (0.0,0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  reset();
  updateEyes();
  createLists();
}

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  //glLoadIdentity();
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  //  glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
  //glOrtho(-7.0, 7.0, -7.0, 7.0, -7.0, 7.0);
  //gluPerspective (0.0, (float)SCREEN_WIDTH/(float)SCREEN_HEIGHT, 0., 7.);
  //glFrustum(-1., 1., -1.0, 1.0, 2.0, 100.0);
  gluPerspective(90.0, (GLfloat) width/height, 0.0, 1.0); 
  glMatrixMode(GL_MODELVIEW); 
  glLoadIdentity();

  glTranslatef(t_x, t_y, t_z);  // move a posicao da camera
  gluLookAt (EYE_X, EYE_Y, EYE_Z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  showCoords(3.0);
  glColor3f(1.0, 1.0, 1.0);
  glutSolidSphere(.07, 50, 50);

  /*  use listas para desenhar
      glEnableClientState (GL_COLOR_ARRAY);
      glEnableClientState (GL_VERTEX_ARRAY);
      glColorPointer (3, GL_FLOAT, 0, colors);
      glVertexPointer (3, GL_FLOAT, 0, vertices);
      /*    
      int i;
      glBegin(GL_TRIANGLES);
      for (i = 0; i < 3; i++)
      glArrayElement(i);
      glEnd();
  */

  glCallList(TRIANGLE_LIST);

  glFlush();
  glutSwapBuffers();
}


void reshape (int w, int h)
{
  glViewport (0, 0, (GLsizei) w, (GLsizei) h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  gluPerspective(90.0, (GLfloat) w/h, 0.0, 1.0); 
  //  gluPerspective(0.0, (GLfloat) w/(GLfloat) h, 0.0, 20.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  width = w;
  height = h;
}


void mousePress (int button, int state, int x, int y)
{
  MOUSE_BUTTON = button;
  MOUSE_STATE = state;
  if (state == GLUT_DOWN) {
    oldX = x;
    oldY = y;
    switch(MOUSE_BUTTON) {
    case GLUT_LEFT_BUTTON:
      break;
    case GLUT_MIDDLE_BUTTON:
      break;
    case GLUT_RIGHT_BUTTON:
      break;
    default:
      break;
    }
    glutPostRedisplay();  
  }
}


void mouseMove (int x, int y)
{
  if (MOUSE_STATE == GLUT_DOWN) {
/*     printf("(RHO, THETA, PHI)= (%.2f, %.2f, %.2f) ", RHO, THETA, PHI); */
/*     printf("(EYE_X, EYE_Y, EYE_Z)= (%.2f, %.2f, %.2f)\n", EYE_X, EYE_Y, EYE_Z); */
    switch(MOUSE_BUTTON) {
    case GLUT_LEFT_BUTTON:
      updateAngles(x, y);
      break;
    case GLUT_MIDDLE_BUTTON:
      break;
    case GLUT_RIGHT_BUTTON:
      RHO += (y - oldY) * 0.01;
      if (RHO < 0.5) RHO = 0.5;
      if (RHO > 10.0) RHO = 10.0;
      break;
    default:
      break;
    }
  }
  oldX = x;
  oldY = y;
  updateEyes();
  glutPostRedisplay();
}

// testar essa funcao de zoom
static float zoomFactor; /* Global, if you want. Modified by user input.
			    Initially 1.0 */ 
/* A routine for setting the projection matrix. May 
   be called from a resize event handler in a typical
   application. Takes integer width and height
   dimensions of the drawing area. Creates a
   projection matrix with correct aspect ratio
   and zoom factor. */ 
/*
  void setProjectionMatrix (int width, int height) {
  glMatrixMode(GL_PROJECTION); 
  glLoadIdentity(); 
  gluPerspective (50.0*zoomFactor, (float)width/(float)height, zNear, zFar);
  }
*/
/* ...Where 'zNear' and 'zFar' are up to you to fill in. */ 

void keyboard(unsigned char key, int x, int y)
{
  switch (key) {
  case 27:
    exit(0);
    break;
  case 'r':
  case 'R':
    reset();
    break;
  case 'a':  // move para esquerda
    t_x -= 0.05;
    break;
  case 's':  // move para baixo
    t_y -= 0.05;
    break;
  case 'd':  // move para direita
    t_x += 0.05;
    break;
  case 'w':  // move para cima
    t_y += 0.05;
    break;
  default:
    //printf("%d apertado\n", key);
    break;
  }
  updateEyes();
  glutPostRedisplay();
}


int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize (SCREEN_WIDTH, SCREEN_HEIGHT);
  glutInitWindowPosition (WINDOW_INIT_POSX, WINDOW_INIT_POSY);
  glutCreateWindow (argv[0]);
  
  glutDisplayFunc(display);
  glutMotionFunc(mouseMove);
  glutMouseFunc(mousePress);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard);

  init ();
  glutMainLoop();
  return 0;
}
